ifndef TOP
TOP:=$(shell X=.; until stat $$X/topstamp 1>/dev/null 2>/dev/null;do X=$$X/..; done;echo $$X)
endif

ifndef DIR
pwd := $(shell pwd;)
DIR:=$(shell basename $(pwd);)
endif

ACFLAGS ?= -v1 -k
AC      ?= $(TOP)/third/ac++
AG      ?= $(TOP)/third/ag++
PCONFIG ?= $(TOP)/third/puma.config
CC =g++
LIBRARY_PATH =$(TOP)/third/libantlr3c/.libs

ext=
preprocessor= 
d_ext=
comp_ext=
a_ext=
ifeq ($(findstring debug,$(MAKECMDGOALS)),debug)
	d_ext=-g
	preprocessor+= -g -DDEBUG
endif
ifeq ($(findstring compact,$(MAKECMDGOALS)),compact)
	comp_ext=-comp
	preprocessor+= -DCOMPACT
endif

ifeq ($(findstring 32,$(MAKECMDGOALS)),32)
	preprocessor+= -m32
else
	preprocessor+= -m64
endif
CSOURCES=${wildcard *.c}
CPPSOURCES=${wildcard *.cpp}
GSOURCES=${wildcard *.g}
HSources=${wildcard *.h}

objects_temp=$(CSOURCES:.c=.o) $(CPPSOURCES:.cpp=.o) 

remove =$(TOP)/.objs/*.o *.d *.out 
ifeq ($(findstring statesFile.g,$(GSOURCES)),statesFile.g)
	objects= statesFileParser.o statesFileLexer.o $(objects_temp)
	remove+= statesFileLexer.c statesFileParser.c statesFileLexer.h statesFileParser.h *.tokens -r output/
else
	ifeq ($(findstring gmini.g,$(GSOURCES)),gmini.g)
		objects= gminiParser.o gminiLexer.o $(objects_temp)
		remove+= gminiLexer.c gminiParser.c gminiLexer.h gminiParser.h *.tokens -r output/
	else
		objects= $(objects_temp)
	endif
endif

ifeq ($(findstring text,$(MAKECMDGOALS)),text)
	visitor= $(TOP)/src/graph/visitor.h
	inc=
else
	inc= -I$(TOP)/src/aspectout/graph -I$(TOP)/src/aspectout/visual
	visitor= $(TOP)/src/aspectout/graph/visitor.h
	ifeq ($(findstring graph,$(DIR)),graph)
		remove+= -r $(TOP)/src/aspectout/
	endif
	a_ext=-a
endif

libs=-L$(LIBRARY_PATH)
gmini_t=gmini$(d_ext)$(a_ext)$(comp_ext)

aspectfile= $(TOP)/src/visual/AShapeVisitor.ah

full_objects=$(addprefix $(TOP)/.objs/,$(objects))
depends=$(objects:.o=.d)
non_priority_depends=$(filter-out %Parser.d %Lexer.d, $(depends))
priority_depends=$(filter-out $(non_priority_depends), $(depends))


DIRECTORIES=$(filter-out %visual %src %aspectout %.svn, $(shell find $(TOP)/src -maxdepth 1 -type d;))
I_DIRECTORIES=$(addprefix -I,$(DIRECTORIES))
libraries=$(DIRECTORIES:$(TOP)/src/%=$(TOP)/lib/lib%.a)

inc+= $(I_DIRECTORIES) -I. -I$(TOP)/third/libantlr3c/include

ifeq ($(findstring graph,$(DIR)),graph)
	ifeq ($(findstring text,$(MAKECMDGOALS)),text)
		targets=$(TOP)/lib/lib$(DIR).a
	else
		targets=$(visitor) $(TOP)/lib/lib$(DIR).a
	endif
	what_to_clean=folder_clean
else 
	ifeq ($(findstring src,$(DIR)),src) 
		targets=subfolders $(TOP)/bin/$(gmini_t)
		what_to_clean=clean_all
	else
		ifeq ($(TOP),.)
			targets=subfolders $(TOP)/bin/$(gmini_t)
			what_to_clean=clean_all
		else
			ifeq ($(findstring bin,$(DIR)),bin) 
				targets=subfolders $(TOP)/bin/$(gmini_t)
				what_to_clean=clean_all
			else
				ifeq ($(findstring translate,$(DIR)),translate) 
					targets=$(TOP)/lib/lib$(DIR).a $(TOP)/lib/lib$(DIR).so
					what_to_clean=folder_clean
					C_FLAGS= -fPIC -Wall
				else
					targets=$(TOP)/lib/lib$(DIR).a
					what_to_clean=folder_clean
				endif
			endif
		endif
	endif
endif


.PHONY: clean clean_all folder_clean subfolders %.o

all : $(targets)

ifeq ($(findstring $(MAKECMDGOALS),clean),)
-include $(depends)
endif

subfolders:
	@for i in $(DIRECTORIES); do \
		cd $$i; $(MAKE) $(MAKECMDGOALS); cd -; \
	done

$(TOP)/bin/$(gmini_t): $(libraries)
	$(CC) -o $(TOP)/bin/$(gmini_t) -L$(TOP)/third/libantlr3c/.libs -lantlr3c $(TOP)/lib/*.a $(TOP)/lib/libgrmr.a $(TOP)/lib/libgraph.a $(TOP)/lib/libcheck.a

$(TOP)/lib/lib$(DIR).a : $(full_objects)
	ar rcs $@ $(full_objects)

$(TOP)/lib/lib$(DIR).so: $(full_objects)
	$(CC) -shared -o $@ $(preprocessor) -Wl,-soname,$@ $(full_objects)

$(TOP)/src/aspectout/graph/visitor.h: $(TOP)/src/graph/visitor.h $(aspectfile)
	$(AC) $(ACFLAGS) --config $(PCONFIG) $(inc) -I$(TOP)/src/visual -p $(TOP)/src/ -a $(aspectfile) -c $< -d $(TOP)/src/aspectout/

#added to force for example to generate Parser, Lexer file before files that include it else, it will result in an error inside g++ -M which will not be catched. since Makefile seems to generate .d files in alphabetical order
$(non_priority_depends):  $(priority_depends)

%.d : %.c
	$(CC) $(inc) $(preprocessor) -M $<  > $@
	
%.d : %.cpp
	$(CC) $(inc) $(preprocessor) -M $<  > $@

#added this rule to make sure dependencies are checked that are included by .d files since those have no relative path
$(TOP)/.objs/%.o : %.o

$(TOP)/.objs/%.o : %.c
	$(CC) -o $(TOP)/.objs/$*.o -c $(C_FLAGS) $(inc) $< $(preprocessor)

$(TOP)/.objs/%.o : %.cpp
	$(CC) -o $(TOP)/.objs/$*.o -c $(C_FLAGS) $(inc) $< $(preprocessor)

%Parser.c %Parser.h %Lexer.c %Lexer.h: %.g
	java -jar $(TOP)/third/antlr-3.2.jar $<

text: all

debug: all

compact: all

32: all

64: all

doxygen:
	doxygen $(TOP)/src/DoxyFile

test:
	@cd $(TOP)/tests/; make ; cd -

clean: $(what_to_clean)

clean_all:
	@for i in $(DIRECTORIES); do \
		cd $$i; $(MAKE) clean;  cd -; \
	done
	rm -f $(TOP)/bin/gmini* $(TOP)/lib/*.a $(TOP)/lib/*.so

folder_clean:
	rm -f $(remove)
